package cn.wizzer.app.crown.modules.services.impl;

import cn.wizzer.app.crown.commons.util.ScanParamsUtil;
import cn.wizzer.app.crown.modules.models.CrownConfig;
import cn.wizzer.app.crown.modules.models.CrownLeague;
import cn.wizzer.app.crown.modules.models.CrownMatch;
import cn.wizzer.app.crown.modules.models.CrownSubResult;
import cn.wizzer.app.crown.modules.models.caches.CrownMatchChampion;
import cn.wizzer.app.crown.modules.models.caches.CrownMatchSimplex;
import cn.wizzer.app.crown.modules.models.constant.CrownConstant;
import cn.wizzer.app.crown.modules.models.constant.CrownRedisConstant;
import cn.wizzer.app.crown.modules.models.enums.MatchStageEnum;
import cn.wizzer.app.crown.modules.models.enums.MatchTypeEnum;
import cn.wizzer.app.crown.modules.models.enums.PlayWayEnum;
import cn.wizzer.app.crown.modules.models.enums.SubResultEnum;
import cn.wizzer.app.crown.modules.services.CrownConfigService;
import cn.wizzer.app.crown.modules.services.CrownLeagueService;
import cn.wizzer.app.crown.modules.services.CrownMatchService;
import cn.wizzer.app.crown.modules.services.CrownSubResultService;
import cn.wizzer.app.crown.modules.services.order.CrownOrderService;
import cn.wizzer.app.crown.modules.services.pl.ft.AllBetsResolverService;
import cn.wizzer.app.crown.modules.services.result.BKMatchResultService;
import cn.wizzer.app.crown.modules.services.result.FTMatchResultService;
import cn.wizzer.app.match.modules.models.constant.Fields;
import cn.wizzer.framework.base.Result;
import cn.wizzer.framework.base.exceptions.BizException;
import cn.wizzer.framework.base.service.BaseServiceImpl;
import cn.wizzer.framework.page.Pagination;
import cn.wizzer.framework.util.JSONUtil;
import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import org.apache.commons.collections.ListUtils;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.pager.Pager;
import org.nutz.dao.sql.Sql;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.springframework.data.redis.core.StringRedisTemplate;
import redis.clients.jedis.ScanParams;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@IocBean(args = {"refer:dao"})
@Service(interfaceClass = CrownMatchService.class)
public class CrownMatchServiceImpl extends BaseServiceImpl<CrownMatch> implements CrownMatchService {

    public CrownMatchServiceImpl(Dao dao) {
        super(dao);
    }

    @Inject
    private RedisService redisService;
    @Inject
    private StringRedisTemplate stringRedisTemplate;
    @Inject
    private CrownOrderService orderService;
    @Inject
    private CrownLeagueService leagueService;
    @Inject
    @Reference(retries = 3, timeout = 500000)
    private CrownConfigService crownConfigService;
    @Inject
    @Reference(retries = 3, timeout = 500000)
    private BKMatchResultService bkMatchResultService;
    @Inject
    @Reference(retries = 3, timeout = 500000)
    private FTMatchResultService ftMatchResultService;
    @Inject
    @Reference(retries = 3, timeout = 500000)
    private CrownSubResultService subResultService;

    @Inject("allBetsResolverServiceImpl")
    @Reference(retries = 3, timeout = 500000)
    private AllBetsResolverService allBetsService;

    @Inject("reAllBetsResolverServiceImpl")
    @Reference(retries = 3, timeout = 500000)
    private AllBetsResolverService reAllBetsService;

    private static final Log log = Logs.get();

    /**
     * 统计玩法数量用到的no1集合
     */
    private ArrayList<Integer> no1List = Result.createList(8, 9, 10, 11, 12, 38);


    @Override
    public CrownMatch queryByTeamInfo(String league, String mbTeam, String tgName, Date dateTime) {
        Cnd cnd = Cnd.where("league", "=", league).and("mb_team", "=", mbTeam)
                .and("tg_team", "=", tgName).and("date_time", "=", dateTime);
        return this.fetch(cnd);
    }

    @Override
    public Pagination matchList(MatchStageEnum stage, String sportType, String keyWord, int pageNo, int pageSize) {
        ScanParams scanParams = ScanParamsUtil.get();
        // ‘今日’、‘早盘’赛事集合过滤已经在滚球中赛事。当stage不是running时，查出滚球赛事id集合。
        List<String> runningMatchKeys = new ArrayList<>();
        if (!MatchStageEnum.RUNNING.equals(stage)) {
            String runningKey = Fields.PREFIX_CROWN + sportType + Fields.KEY_JOIN + PlayWayEnum.R + Fields.KEY_JOIN + MatchStageEnum.RUNNING + Fields.SUFFIX_MATCH;
            scanParams.match(runningKey + ":*");
            runningMatchKeys = redisService.scan("0", scanParams).getResult()
                    .stream()
                    .map(matchStr -> matchStr.replace(MatchStageEnum.RUNNING.VALUE, stage.VALUE))
                    .collect(Collectors.toList());
        }

        // 获取stage参数对应阶段的赛事key的列表
        String key = Fields.PREFIX_CROWN + sportType + Fields.KEY_JOIN + PlayWayEnum.R + Fields.KEY_JOIN + stage + Fields.SUFFIX_MATCH;
        scanParams.match(key + ":*");
        List<String> stageMatchKeys = redisService.scan("0", scanParams).getResult();

        // 集合中过滤‘滚球中’赛事
        stageMatchKeys.removeAll(runningMatchKeys);

        // match字符串转换成pojo
        Stream<CrownMatch> stream = stringRedisTemplate.opsForValue()
                .multiGet(stageMatchKeys)
                .stream()
                .map(matchStr ->
                        JSONUtil.parseStringToJavaBean(CrownMatch.class, matchStr)
                );
        // 搜索条件
        if (Strings.isNotBlank(keyWord)) {
            stream = stream.filter(match ->
                    (Strings.isNotBlank(match.getMbTeam()) && match.getMbTeam().contains(keyWord))
                            || (Strings.isNotBlank(match.getTgTeam()) && match.getTgTeam().contains(keyWord))
                            || (Strings.isNotBlank(match.getLeague()) && match.getLeague().contains(keyWord)));
        }
        //时间排序
        stream = stream.sorted(Comparator.comparingLong(CrownMatch::getDateTimestamp));
        //分页
        List<CrownMatch> lrange = stream.collect(Collectors.toList());
        int endIndex = pageNo == 0 ? pageSize : pageNo * pageSize;
        int count = lrange.size();
        int startIndex = endIndex - pageSize;
        lrange = lrange.subList(pageNo == 0 ? 0 : startIndex, endIndex == 0 ? count : Math.min(endIndex, count));
        // 设置分页属性
        Pagination pagination = new Pagination();
        pagination.setTotalCount(count);
        pagination.setPageNo(pageNo);
        pagination.setPageSize(pageSize);
        //设置玩法数据
        stream = lrange.stream().map(match -> {
            // redis中获取所有玩法list
            return this.composeMatch(CrownRedisConstant.SIMPLEX, match);
        });
        lrange = stream.collect(Collectors.toList());
        pagination.setList(lrange);
        return pagination;
    }


    @Override
    public Pagination p3MatchList(String sportType, String keyWord, int pageNo, int pageSize) {
        ScanParams scanParams = ScanParamsUtil.get();
        // 查询滚球中的赛事
        String runningKey = Fields.PREFIX_CROWN + sportType + Fields.KEY_JOIN + PlayWayEnum.R + Fields.KEY_JOIN + MatchStageEnum.RUNNING + Fields.SUFFIX_MATCH;
        scanParams.match(runningKey + ":*");
        List<String> runningMatchKeys = redisService.scan("0", scanParams).getResult()
                .stream()
                .map(matchStr -> matchStr.replace(MatchStageEnum.RUNNING.VALUE, PlayWayEnum.P3.getType()))
                .collect(Collectors.toList());


        String key = Fields.PREFIX_CROWN + sportType + Fields.KEY_JOIN + PlayWayEnum.P3 + Fields.ALL_STAGE + Fields.SUFFIX_MATCH;
        scanParams.match(key + ":*");
        List<String> p3MatchKeys = redisService.scan("0", scanParams).getResult();

        // 集合中过滤‘滚球中’的赛事
        p3MatchKeys.removeAll(runningMatchKeys);

        Stream<CrownMatch> stream = stringRedisTemplate.opsForValue()
                .multiGet(p3MatchKeys)
                .stream()
                .map(matchStr ->
                        JSONUtil.parseStringToJavaBean(CrownMatch.class, matchStr)
                );
        // 搜索条件
        if (Strings.isNotBlank(keyWord)) {
            stream = stream.filter(match ->
                    (Strings.isNotBlank(match.getMbTeam()) && match.getMbTeam().contains(keyWord))
                            || (Strings.isNotBlank(match.getTgTeam()) && match.getTgTeam().contains(keyWord))
                            || (Strings.isNotBlank(match.getLeague()) && match.getLeague().contains(keyWord)));
        }
        //时间排序
        stream = stream.sorted(Comparator.comparingLong(CrownMatch::getDateTimestamp));
        //分页
        List<CrownMatch> lrange = stream.collect(Collectors.toList());
        int endIndex = pageNo == 0 ? pageSize : pageNo * pageSize;
        int count = lrange.size();
        int startIndex = endIndex - pageSize;
        lrange = lrange.subList(pageNo == 0 ? 0 : startIndex, endIndex == 0 ? count : Math.min(endIndex, count));
        // 设置分页属性
        Pagination pagination = new Pagination();
        pagination.setTotalCount(count);
        pagination.setPageNo(pageNo);
        pagination.setPageSize(pageSize);
        //设置玩法数据
        stream = lrange.stream().map(match -> this.composeMatch(CrownRedisConstant.P3, match));
        lrange = stream.collect(Collectors.toList());
        pagination.setList(lrange);
        return pagination;
    }

    @Override
    public Pagination championList(String sportType, String keyWord, int pageNo, int pageSize) {
        // CROWN_FOOTBALL_FS_LEAGUE
        String redisKey = Fields.PREFIX_CROWN + sportType + Fields.KEY_JOIN + PlayWayEnum.FS + Fields.SUFFIX_LEAGUE;
        ScanParams scanParams = new ScanParams();
        scanParams.count(Integer.MAX_VALUE);
        scanParams.match(redisKey + ":*");

        Stream<CrownLeague> stream = stringRedisTemplate.opsForValue()
                .multiGet(redisService.scan("0", scanParams).getResult())
                .stream()
                .map(matchStr ->
                        JSONUtil.parseStringToJavaBean(CrownLeague.class, matchStr)
                );
        if (Strings.isNotBlank(keyWord)) {
            stream = stream.filter(league ->
                    (Strings.isNotBlank(league.getChampionName()) && league.getChampionName().contains(keyWord))
                            || (Strings.isNotBlank(league.getLeague()) && league.getLeague().contains(keyWord)));
        }
        //时间排序
        stream = stream.sorted(Comparator.comparingLong(CrownLeague::getDateTimestamp));
        //分页
        List<CrownLeague> lrange = stream.collect(Collectors.toList());
        int endIndex = pageNo == 0 ? pageSize : pageNo * pageSize;
        int count = lrange.size();
        int startIndex = endIndex - pageSize;
        lrange = lrange.subList(pageNo == 0 ? 0 : startIndex, endIndex == 0 ? count : Math.min(endIndex, count));
        // 设置分页属性
        Pagination pagination = new Pagination();
        pagination.setTotalCount(count);
        pagination.setPageNo(pageNo);
        pagination.setPageSize(pageSize);
        //设置玩法数据
        stream = lrange.stream().map(league -> {
            scanParams.match(CrownRedisConstant.CHAMPION + league.getId() + "*");
            //redis中读取各个队伍具体赔率
            List<CrownMatchChampion> championList = redisService.lrange(CrownRedisConstant.CHAMPION + league.getId(), 0, -1)
                    .stream()
                    // String类型转CrownMatchChampion类型
                    .map(champion ->
                            (CrownMatchChampion) JSONUtil.parseStringToJavaBean(CrownMatchChampion.class, champion)
                    )
                    //费率为零则舍弃
                    .filter(champion -> null != champion.getOdds() && champion.getOdds().compareTo(BigDecimal.ZERO) != 0)
                    .collect(Collectors.toList());
            //设置到属性中
            league.setMatchChampionList(championList);
            return league;
        });
        lrange = stream.collect(Collectors.toList());
        pagination.setList(lrange);
        return pagination;
    }

    @Override
    public CrownMatch composeMatch(String redisKey, CrownMatch match) {
        ScanParams scanParams = ScanParamsUtil.get().match(redisKey + match.getId() + "*");
        //redis中读取玩法数据
        List<String> allBetsList = redisService.scan("0", scanParams).getResult();
        List<CrownMatchSimplex> simplexes = stringRedisTemplate.opsForValue()
                .multiGet(allBetsList)
                .stream()
                .map(simplex ->
                        //单式数据获取
                        (CrownMatchSimplex) JSONUtil.parseStringToJavaBean(CrownMatchSimplex.class, simplex)
                )
                .collect(Collectors.toList());
        // 统计所有玩法数
        int playsNum = this.countPlaysNum(simplexes);
        match.setAllPlayWayNum(playsNum);
        match.setMatchSimplexList(simplexes);
        return match;
    }

    @Override
    public CrownMatch crawlerAllBets(Map<String, String> subscribeParam) {
        String matchId = subscribeParam.get("subscribe");
        PlayWayEnum playWay = PlayWayEnum.valueOf(subscribeParam.get("playWay"));
        String stage = PlayWayEnum.P3.equals(playWay) ? Fields.ALL_STAGE : Fields.KEY_JOIN + subscribeParam.get("stage");
        // 拼接redisKey
        String key = Fields.PREFIX_CROWN + "*" + Fields.KEY_JOIN + playWay + stage + Fields.SUFFIX_MATCH + Fields.KEY_COLON + matchId;
        // 从redis中查出订阅的赛事
        List<String> matchList = redisService.scan("0", ScanParamsUtil.get().match(key)).getResult();
        // 根据赛事id查询，正常只有一条。
        if (matchList.size() == 1) {
            CrownMatch match = JSONUtil.parseStringToJavaBean(CrownMatch.class, redisService.get(matchList.get(0)));
            log.info("订阅成功,开始爬取所有玩法,matchId:" + matchId);
            // 获取账号
            CrownConfig crownConfig = crownConfigService.syncOne("订阅成功时爬取所有玩法");
            if (null != crownConfig) {
                try {
                    // 爬取所有玩法
                    AllBetsResolverService service = (Fields.KEY_JOIN + CrownConstant.RUNNING.toUpperCase()).equals(stage)
                            ? reAllBetsService : allBetsService;
                    return service.crawler(playWay, match, crownConfig);
                } catch (BizException e) {
                    log.error(e.getRemand());
                } finally {
                    crownConfigService.release(crownConfig);
                }
            } else {
                log.error("订阅爬取所有玩法失败,没有可用账号");
            }
        } else {
            log.error("订阅爬取所有玩法失败,赛事:" + matchList + "。redisKey:" + key);
        }
        return null;
    }

    /**
     * 统计每场比赛玩法的数量
     *
     * @param simplexList
     * @return
     */
    private int countPlaysNum(List<CrownMatchSimplex> simplexList) {
        HashSet<String> set = new HashSet<>();
        // 统计玩法数量过滤赔率为null或0
        simplexList.stream()
                .filter(simplex -> null != simplex.getOdds() && BigDecimal.ZERO.compareTo(simplex.getOdds()) != 0)
                .forEach(simplex -> {
                    int no1 = simplex.getNo1();
                    // 如果是波胆、半全场等玩法字符串截取到no1
                    if (no1List.contains(no1)) {
                        set.add(String.valueOf(no1));
                    } else {
                        set.add(simplex.getNo1() + Fields.KEY_COLON + simplex.getNo2());
                    }
                });
        return set.size();
    }

    @Override
    public Pagination results(String start, String end, PlayWayEnum playWay, Pager pager, String sportType) {
        if (PlayWayEnum.FS.equals(playWay)) {
            return leagueService.results(start, end, pager, sportType);
        } else {
            Sql sql = Sqls.create("select * from crown_match $condition ");
            Sql countSql = Sqls.create("select count(1) from crown_match $condition ");
            Cnd cnd = Cnd.where("date_time", ">=", start)
                    .and("date_time", "<=", end)
                    .and("type", "=", sportType)
                    .and(Cnd.exps("stage", "=", CrownConstant.FINISHED)
                            .or("stage", "=", CrownConstant.OTHER));
            sql.setCondition(cnd);
            countSql.setCondition(cnd);
            return this.listPage(pager.getPageNumber(), pager.getPageSize(), sql, countSql);
        }
    }

    @Override
    public void crawlMatchResult(Long startTime, Long endTime) {
        // 获取爬虫账号
        CrownConfig crownConfig = crownConfigService.syncOne("手动获取赛果任务");
        if (crownConfig != null) {
            log.info("准备开始任务:" + crownConfig);
            try {
                // 一天的毫秒值
                long oneDayMilliSecond = 24 * 60 * 60 * 1000;
                // 计算要爬取的天数
                long dayNum = (endTime - startTime) / oneDayMilliSecond + 1;
                // 如果不限制天数爬虫程序可能会超时
                if (dayNum > 2) {
                    throw new BizException("选择1天进行爬取");
                }
                // 处理日期格式
                String start = DateFormatUtils.format(startTime, "yyyy-MM-dd HH:mm:ss");
                String end = DateFormatUtils.format(endTime, "yyyy-MM-dd HH:mm:ss");
                // 查询日期范围内所有状态不是finished的赛事
                Cnd cnd = Cnd.NEW();
                cnd.where().andBetween("date_time", start, end)
                        .and("stage", "!=", "finished").and("stage", "!=", "other");
                List<CrownMatch> list = this.query(cnd);
                for (int i = 0; i < list.size(); i++) {
                    // 爬足球赛果
                    ftMatchResultService.crawler(list.get(i), crownConfig);
                    // 爬篮球赛果
                    bkMatchResultService.crawler(list.get(i), crownConfig);
                }
            } finally {
                // 获取账号，判断是否为空，以防账号已经被清除
                crownConfigService.release(crownConfig);
            }
        } else {
            throw new BizException("没有可用的账号");
        }

    }


    @Override
    public List matchCount() {
        List<Map> result = new ArrayList<>();
        ScanParams scanParams = new ScanParams();
        scanParams.count(Integer.MAX_VALUE);
        // 赛事类型集合（FOOTBALL、BASKETBALL）
        List<MatchTypeEnum> matchTypeEnumList = EnumUtils.getEnumList(MatchTypeEnum.class);
        // 赛事状态集合（FUTURE、BROWSE、RUNNING）
        List<MatchStageEnum> matchStageEnumList = EnumUtils.getEnumList(MatchStageEnum.class);
        for (MatchTypeEnum matchTypeEnum : matchTypeEnumList) {
            for (MatchStageEnum matchStageEnum : matchStageEnumList) {
                // 拼接单式玩法redis key(CROWN_FOOTBALL_BROWSE_MATCH)
                String simplexMatchKey = Fields.PREFIX_CROWN + matchTypeEnum + Fields.KEY_JOIN + PlayWayEnum.R + Fields.KEY_JOIN + matchStageEnum + Fields.SUFFIX_MATCH;
                // 拼接冠军redis key
                String championKey = Fields.PREFIX_CROWN + matchTypeEnum + Fields.KEY_JOIN + PlayWayEnum.FS + Fields.SUFFIX_LEAGUE;
                // 拼接综合redis key
                String p3Key = Fields.PREFIX_CROWN + matchTypeEnum + Fields.KEY_JOIN + PlayWayEnum.P3 + Fields.ALL_STAGE + Fields.SUFFIX_MATCH;
                // 获取单式赛事统计数量
                scanParams.match(simplexMatchKey + ":*");
                int simplexMatchCount = redisService.scan("0", scanParams).getResult().size();
                // 获取冠军赛事统计数量
                scanParams.match(championKey + ":*");
                int championCount = redisService.scan("0", scanParams).getResult().size();
                // 获取综合赛事统计数量
                scanParams.match(p3Key + ":*");
                int p3MatchCount = redisService.scan("0", scanParams).getResult().size();


                // 今日、早盘赛事总数量 = 赛事数量 + 冠军联赛数量
                if (MatchStageEnum.BROWSE.equals(matchStageEnum) || MatchStageEnum.FUTURE.equals(matchStageEnum)) {
                    simplexMatchCount = simplexMatchCount + championCount;
                }

                result.add(
                        Result.createMap(
                                Fields.MATCH_COUNT_FIELD_TYPE, matchTypeEnum,
                                Fields.MATCH_COUNT_FIELD_STAGE, matchStageEnum,
                                Fields.MATCH_COUNT_FIELD_COUNT, simplexMatchCount
                        )
                );
            }
        }
        return result;
    }

    @Override
    public CrownMatch subResult(String id, Integer oldVersion) {
        CrownMatch match = this.fetch(id);
        Cnd cnd = Cnd.where("match_id", "=", id);
        // 如果传入的版本为空，查询最新版本
        if (null == oldVersion) {
            oldVersion = match.getVersion();
        }
        cnd.and("version", "=", oldVersion);
        List<CrownSubResult> list = subResultService.query(cnd.orderBy("tag", "asc"));
        match.setSubResults(list);
        return match;
    }

    @Override
    @Aop(TransAop.REPEATABLE_READ)
    public void updateMatchResult(CrownMatch match, String platformUid) {
        // 记录操作人
        match.setOpBy(platformUid);
        // 比分校验
        this.checkMatchScore(match);
        List<CrownSubResult> subResults = match.getSubResults();
        // 版本号从0开始
        int version = 0;
        // 根据赛事id查询赛果详情
        Cnd cnd = Cnd.where("match_id", "=", match.getId());
        // 如果match的version不为空，查询最新的version
        if (null != match.getVersion()) {
            cnd.and("version", "=", match.getVersion());
        }
        List<CrownSubResult> oldSubResults = subResultService.query(cnd);
        // 记录旧版本号
        Integer oldVersion = null;
        // 把查出的赛果集合和要更新的赛果集合做比较，判断版本号用不用更新
        if (CollectionUtils.isNotEmpty(oldSubResults)) {
            oldVersion = oldSubResults.get(0).getVersion();
            // 如果集合相同返回提示信息
            if (ListUtils.isEqualList(oldSubResults, subResults)) {
                Result.breakWith("请勿填入相同的赛果");
            }
            // 当‘增加’赛果条数时
            if (oldSubResults.size() < subResults.size()) {
                // 如果与之前的赛果相比，比分一致，则版本号不增加
                if (subResults.containsAll(oldSubResults)) {
                    // 集合中删除已存在的赛果
                    subResults.removeAll(oldSubResults);
                } else {
                    // 赛果比分不一致，版本号在原来的基础之上加1
                    version = oldVersion + 1;
                }
            }
            // 减少赛果或条目数量相等，版本号在原来的基础之上加1
            else {
                version = oldVersion + 1;
            }
        }
        for (int i = 0; i < subResults.size(); i++) {
            CrownSubResult subResult = subResults.get(i);
            // 后台修改赛果需要给match、subResult个别属性赋值。爬虫的已经赋值好了
            if (!"task".equals(platformUid)) {
                // 足球半场是NO4
                if ("NO4".equals(subResult.getTag()) && MatchTypeEnum.FOOTBALL.equals(match.getType())) {
                    match.setMbInBallHf(subResult.getResultH());
                    match.setTgInBallHf(subResult.getResultC());
                }
                // 篮球半场是NO5
                if ("NO5".equals(subResult.getTag()) && MatchTypeEnum.BASKETBALL.equals(match.getType())) {
                    match.setMbInBallHf(subResult.getResultH());
                    match.setTgInBallHf(subResult.getResultC());
                }
                if ("NO8".equals(subResult.getTag())) {
                    match.setMbInBall(subResult.getResultH());
                    match.setTgInBall(subResult.getResultC());
                }
                subResult.setGameType(match.getType());
                subResult.setMatchId(match.getId());
                subResult.setType(SubResultEnum.GOALS_NUM);
            }
            // 设置版本号
            subResult.setVersion(version);
            // 记录操作人
            subResult.setOpBy(platformUid);
        }
        // 设置赛事版本
        match.setVersion(version);
        // 赛果详情入库
        subResultService.fastInsert(subResults);
        // 更新赛事比分、状态
        this.updateIgnoreNull(match);
        // 如果match版本有变化则重新结算
        if (null != oldVersion && version != oldVersion) {
            orderService.reSettle(match);
        }
    }



    /**
     * 更新赛果时比分校验
     *
     * @param match
     */
    private void checkMatchScore(CrownMatch match) {
        List<CrownSubResult> subResults = match.getSubResults();
        if (CollectionUtils.isEmpty(subResults)) {
            Result.breakWith("赛果不能为空" + ("task".equals(match.getOpBy()) ? ":" + match : ""));
        }

        Map<String, CrownSubResult> resultMap = subResults.stream()
                .collect(Collectors.toMap(CrownSubResult::getTag, Function.identity(), (key1, key2) -> key2));
        // 足球比分校验
        if (MatchTypeEnum.FOOTBALL.equals(match.getType())) {
            // 校验全部8个阶段比分
            if (8 == subResults.size()) {
                // 如果设置比赛状态为other或腰斩，则不校验比分
                if (match.getIsCut() || CrownConstant.OTHER.equals(match.getStage())) {
                    return;
                }
                // 累加主队上半场比分
                int halfInBallH = Integer.parseInt(resultMap.get("NO1").getResultH())
                        + Integer.parseInt(resultMap.get("NO2").getResultH())
                        + Integer.parseInt(resultMap.get("NO3").getResultH());
                // 累加主队全场比分
                int fullInBallH = Integer.parseInt(resultMap.get("NO4").getResultH())
                        + Integer.parseInt(resultMap.get("NO5").getResultH())
                        + Integer.parseInt(resultMap.get("NO6").getResultH())
                        + Integer.parseInt(resultMap.get("NO7").getResultH());
                // 累加客队上半场比分
                int halfInBallC = Integer.parseInt(resultMap.get("NO1").getResultC())
                        + Integer.parseInt(resultMap.get("NO2").getResultC())
                        + Integer.parseInt(resultMap.get("NO3").getResultC());
                // 累加客队全场比分
                int fullInBallC = Integer.parseInt(resultMap.get("NO4").getResultC())
                        + Integer.parseInt(resultMap.get("NO5").getResultC())
                        + Integer.parseInt(resultMap.get("NO6").getResultC())
                        + Integer.parseInt(resultMap.get("NO7").getResultC());

                if (halfInBallH != Integer.parseInt(resultMap.get("NO4").getResultH())) {
                    Result.breakWith("主队半场比分累加错误" + ("task".equals(match.getOpBy()) ? "&&" + JSONUtil.toJSONString(match) : ""));
                }
                if (fullInBallH != Integer.parseInt(resultMap.get("NO8").getResultH())) {
                    Result.breakWith("主队全场比分累加错误" + ("task".equals(match.getOpBy()) ? "&&" + JSONUtil.toJSONString(match) : ""));
                }
                if (halfInBallC != Integer.parseInt(resultMap.get("NO4").getResultC())) {
                    Result.breakWith("客队半场比分累加错误" + ("task".equals(match.getOpBy()) ? "&&" + JSONUtil.toJSONString(match) : ""));
                }
                if (fullInBallC != Integer.parseInt(resultMap.get("NO8").getResultC())) {
                    Result.breakWith("客队全场比分累加错误" + ("task".equals(match.getOpBy()) ? "&&" + JSONUtil.toJSONString(match) : ""));
                }
            }
            // 校验半场、全场比分
            else if (2 == subResults.size()) {
                // 不能缺少半场、全场比分
                if (null == resultMap.get("NO4")) {
                    Result.breakWith("缺少半场比分数据" + ("task".equals(match.getOpBy()) ? "&&" + JSONUtil.toJSONString(match) : ""));
                }
                if (null == resultMap.get("NO8")) {
                    Result.breakWith("缺少全场比分数据" + ("task".equals(match.getOpBy()) ? "&&" + JSONUtil.toJSONString(match) : ""));
                }
            }
            // 校验半场比分
            else if (1 == subResults.size()) {
                if (null == resultMap.get("NO4")) {
                    Result.breakWith("只能勾选半场数据" + ("task".equals(match.getOpBy()) ? "&&" + JSONUtil.toJSONString(match) : ""));
                }
            }
        }
        // 篮球比分校验
        else if (MatchTypeEnum.BASKETBALL.equals(match.getType())) {
            // 赛果条目数量为8
            if (8 == subResults.size()) {
                // 如果设置比赛状态为other，则不校验比分。因为赛果都是字符串汉字‘比赛取消’..
                if (CrownConstant.OTHER.equals(match.getStage())) {
                    return;
                }
                // 主队加时比分
                int overTimeH = "-".equals(resultMap.get("NO7").getResultH())
                        ? 0 : Integer.parseInt(resultMap.get("NO7").getResultH());
                // 客队加时比分
                int overTimeC = "-".equals(resultMap.get("NO7").getResultC())
                        ? 0 : Integer.parseInt(resultMap.get("NO7").getResultC());
                // 累加主队上半场比分
                int firstHalfH = Integer.parseInt(resultMap.get("NO1").getResultH())
                        + Integer.parseInt(resultMap.get("NO2").getResultH());
                // 累加主队下半场比分（第三节 + 第四节 + 加时）
                int secondHalfH = Integer.parseInt(resultMap.get("NO3").getResultH())
                        + Integer.parseInt(resultMap.get("NO4").getResultH()) + overTimeH;
                // 累加客队上半场比分
                int firstHalfC = Integer.parseInt(resultMap.get("NO1").getResultC())
                        + Integer.parseInt(resultMap.get("NO2").getResultC());
                // 累加客队下半场比分（第三节 + 第四节 + 加时）
                int secondHalfC = Integer.parseInt(resultMap.get("NO3").getResultC())
                        + Integer.parseInt(resultMap.get("NO4").getResultC()) + overTimeC;
                // 皇冠赛果大量前四节比分为0，排除检验
                if (!"task".equals(match.getOpBy())) {
                    if (firstHalfH != Integer.parseInt(resultMap.get("NO5").getResultH())) {
                        Result.breakWith("主队上半场比分累加错误" + ("task".equals(match.getOpBy()) ? "&&" + JSONUtil.toJSONString(match) : ""));
                    }
                    if (secondHalfH != Integer.parseInt(resultMap.get("NO6").getResultH())) {
                        Result.breakWith("主队下半场比分累加错误" + ("task".equals(match.getOpBy()) ? "&&" + JSONUtil.toJSONString(match) : ""));
                    }
                    if (firstHalfC != Integer.parseInt(resultMap.get("NO5").getResultC())) {
                        Result.breakWith("客队上半场比分累加错误" + ("task".equals(match.getOpBy()) ? "&&" + JSONUtil.toJSONString(match) : ""));
                    }
                    if (secondHalfC != Integer.parseInt(resultMap.get("NO6").getResultC())) {
                        Result.breakWith("客队下半场比分累加错误" + ("task".equals(match.getOpBy()) ? "&&" + JSONUtil.toJSONString(match) : ""));
                    }
                }
                // 主队全场比分 =  上半场比分 + 下半场比分
                int fullH = Integer.parseInt(resultMap.get("NO5").getResultH()) + Integer.parseInt(resultMap.get("NO6").getResultH());
                // 客队全场比分 = 上半场比分 + 下半场比分
                int fullC = Integer.parseInt(resultMap.get("NO5").getResultC()) + Integer.parseInt(resultMap.get("NO6").getResultC());
                if (fullH != Integer.parseInt(resultMap.get("NO8").getResultH())) {
                    Result.breakWith("主队全场比分累加错误" + ("task".equals(match.getOpBy()) ? "&&" + JSONUtil.toJSONString(match) : ""));
                }
                if (fullC != Integer.parseInt(resultMap.get("NO8").getResultC())) {
                    Result.breakWith("客队全场比分累加错误" + ("task".equals(match.getOpBy()) ? "&&" + JSONUtil.toJSONString(match) : ""));
                }
            } else if (1 == subResults.size()) {
                if (null == resultMap.get("NO4")) {
                    Result.breakWith("只能勾选半场数据" + ("task".equals(match.getOpBy()) ? "&&" + JSONUtil.toJSONString(match) : ""));
                }
            }
        } else {
            Result.breakWith("赛事类型错误：" + match.getType());
        }
    }


}
